﻿//  --------------------------------
//  Copyright (c) AW Systems, Inc. All rights reserved.
//  This source code is made available under the terms of the Microsoft Public License (Ms-PL)
//  http://www.codeplex.com/SLAM/license
//  ---------------------------------

using System;
using AWS.SLAM.Configuration;
using AWS.SLAM.Data;
using AWS.SLAM.Events;
using AWS.SLAM.Hierarchy.Data;
using AWS.SLAM.Logging;
using Microsoft.SharePoint;

namespace AWS.SLAM.Hierarchy
{
    /// <summary>
    /// HierarchicalContentTypeItemCreator adds an item to SLAM's datasource(s) when a new List Item 
    /// configured to be managed by SLAM according to its Content Type is added in SharePoint then
    /// establishes its initial position in the hierarchy of items also managed by SLAM.  
    /// 
    /// A Content Type in SharePoint configured to use the HierarchicalContentTypeCreator requires that it contain
    /// a field of type HierarchyPositionField.
    /// </summary>
    public class HierarchicalContentTypeItemCreator : ContentTypeItemCreator
    {
        #region Private State

        /// <summary>
        /// SLAM Data service layer
        /// </summary>
        private IDataServices _dataServices;

        /// <summary>
        /// SLAM Configuration
        /// </summary>
        private IConfigurationManager _configuration;

        /// <summary>
        /// SLAM Logger
        /// </summary>
        private ILogger _logger;

        #endregion

        #region Constructors

        /// <summary>
        /// Creates instance of HierarchicalContentTypeItemCreator for the given 
        /// DataServices, Configuration, and Logger.
        /// </summary>
        /// <param name="dataServices"></param>
        /// <param name="configuration"></param>
        /// <param name="logger"></param>
        public HierarchicalContentTypeItemCreator(IDataServices dataServices, IConfigurationManager configuration, ILogger logger)
            : base(dataServices, configuration, logger)
        {
            _dataServices = dataServices;
            _configuration = configuration;
            _logger = logger;
        }

        #endregion

        /// <summary>
        /// Adds a new item to SLAM's external datasource then uses the value of the HierarchyPositionField
        /// that must be present in the given listItem to insert the item into the hierarchy
        /// managed by SLAM for the List Item's Content Type.
        /// </summary>
        /// <param name="listItem"></param>
        /// <returns></returns>
        public override bool Create(SPListItem listItem)
        {
            //Execute default SLAM Create process for a configured Content Type
            bool createResult = base.Create(listItem);

            string typeName = SlamItemContext.TypeName;

            //Open Hierarchy's DataService with the Default ConnectionString and DataSchema.
            //This process assumes the Hierarchy is saved in a SQL Server database and is using
            //a SLAM XML Configuration file.
            DataService dataService = new DataService(_configuration.GetSection<ConnectionStringSection>("ConnectionStrings").Default, 
                ((XmlSqlDataMapping)_configuration.DataMapping).GetDataSchema());

            //Check configuration for the presence of a TableName for the listItem's
            //ContentType.  If it is present, use it as the item's typeName instead of the
            //ContentType Name.  Otherwise if it is not present use the ContentType's Name
            string itemTypeName = _configuration.DataMapping.GetTypeAttribute("", typeName, "TableName");
            if (String.IsNullOrEmpty(itemTypeName))
            {
                itemTypeName = typeName;
            }

            //For this type, add the Hierarchy "Left", "Right", and "Hierarchy Level" columns
            //in the SLAM table if they do not exist.
            dataService.AddHierarchyColumns(itemTypeName);

            //Get the Hierarchy Position Field's value from the listItem regardless of its name
            string hierarchyPositionFieldValue = listItem.GetHierarchyPositionFieldValue();

            if (!String.IsNullOrEmpty(hierarchyPositionFieldValue))
            {
                //The Hierarchy Position Field's value has at least 2 parts, the first
                //part contains a Parent GUID Id, the second part contains a sibling
                //ListItem GUID Id.  
                string[] fieldValueParts = hierarchyPositionFieldValue.Split('|');
                if (fieldValueParts.Length >= 2 && !String.IsNullOrEmpty(fieldValueParts[0]))
                {
                    //If the first part is an Empty Guid then this listItem is a root node. Otherwise
                    //add as a child node
                    if (fieldValueParts[0] != Guid.Empty.ToString())
                    {
                        //If the second part is an Empty Guid then this listItem goes at the end
                        //of the parent's children, otherwise it goes to the left, in place, of the
                        //sibling defined by fieldValuesParts[1]
                        if (!String.IsNullOrEmpty(fieldValueParts[1]) && fieldValueParts[1] != Guid.Empty.ToString())
                        {
                            dataService.AddAsLeftSiblingNode(itemTypeName, fieldValueParts[1], listItem.UniqueId.ToString());
                        }
                        else
                        {
                            dataService.AddAsLastChildNode(itemTypeName, fieldValueParts[0], listItem.UniqueId.ToString());
                        }
                    }
                    else
                    {
                        dataService.AddAsRootNode(itemTypeName, listItem.UniqueId.ToString());
                    }

                    dataService.RecalculateHierarchyLevels(itemTypeName);
                }
            }
            return createResult;
        }
    }
}
